#pragma once
#include <iostream>
#include <string>
#include <assert.h>
#include <functional>
#include <unordered_map>
#include "Sock.hpp"
#include "Log.hpp"
#include "Err.hpp"
#include "Epoller.hpp"
#include "Util.hpp"
#include "Protocol.hpp"
using namespace std;
using namespace protocol_ns;
class Connection;
class EpollServer;
const static int gport = 8888;
using func_t = std::function<Response(const Request &)>;
using callback_t = std::function<void(Connection *)>;

// 未来每一个文件描述符（套接字）都要有connection对象
class Connection
{
public:
    Connection(const int &fd, const string &clientip, const uint16_t &clientport)
        : fd_(fd),
          clientip_(clientip),
          clientport_(clientport)
    {
    }
    ~Connection()
    {
    }
    void Register(callback_t recver, callback_t sender, callback_t excepter)
    {
        recver_ = recver;
        sender_ = sender;
        excepter_ = excepter;
    }

public:
    // IO info
    int fd_;
    // 每一个文件描述符自己的缓冲区
    string inbuffer_;
    string outbuffer_;

    // IO处理函数
    callback_t recver_;
    callback_t sender_;
    callback_t excepter_;

    // clientinfo
    string clientip_;
    uint16_t clientport_;

    uint32_t events_;
    EpollServer *R;
};

class EpollServer
{
    const static int gnum = 64;

public:
    EpollServer(func_t func, uint16_t port = gport) : func_(func), port_(port)
    {
    }

    void InitServer()
    {
        // 创建listen套接字 绑定 监听
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();

        // 创建epoll模型
        epoller_.Create();
        logMessage(Debug, "init server success");

        // 2.将listen套接字的connection对象添加到unordered_map
        AddConnection(listensock_.Fd(), EPOLLIN);
    }
    // 事件派发
    void Dispatcher()
    {
        int timeout = 1000;
        while (true)
        {
            LoopOnce(timeout);
        }
    }
    void LoopOnce(int timeout)
    {
        int n = epoller_.Wait(revs_, gnum, timeout);

        for (int i = 0; i < n; i++)
        {
            int fd = revs_[i].data.fd;
            uint32_t events = revs_[i].events;

            logMessage(Debug, "当前正在处理%d上的%s", fd, (events & EPOLLIN) ? "EPOLLIN" : "OTHER");
            // 将所有的异常情况，最后全部转化成为recv，send的异常！
            if ((events & EPOLLERR) || (events & EPOLLHUP))
                events |= (EPOLLIN | EPOLLOUT);

            if ((events & EPOLLIN) && ConnIsExists(fd))
                connections_[fd]->recver_(connections_[fd]);
            if ((events & EPOLLOUT) && ConnIsExists(fd))
                connections_[fd]->sender_(connections_[fd]);
            // if((events&EPOLLERR)||(events&EPOLLHUP)) connections_[fd]->excepter_(connections_[fd]);
        }
    }
    //
    void AddConnection(int fd, uint32_t events, string ip = "127.0.0.1", uint16_t port = gport)
    {
        // 设置fd非阻塞
        if (events & EPOLLET)
            Util::SetNonBlock(fd);
        // 构建connection对象，添加进unorder_map来管理
        Connection *con = new Connection(fd, ip, port);
        // 注册回调
        if (fd == listensock_.Fd())
        {
            con->Register(std::bind(&EpollServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
        }
        else
        {
            con->Register(std::bind(&EpollServer::Recver, this, std::placeholders::_1),
                          std::bind(&EpollServer::Sender, this, std::placeholders::_1),
                          std::bind(&EpollServer::Excepter, this, std::placeholders::_1));
        }
        con->events_ = events;
        con->R = this;
        connections_.insert(std::pair<int, Connection *>(fd, con));
        // fd&&event写到内核中 用户-》内核
        bool r = epoller_.AddModEvent(fd, events, EPOLL_CTL_ADD);
        assert(r);
        (void)r;
        logMessage(Debug, "Addconnection succes,fd:%d,clientinfo:[%s,%d]", con->fd_, ip.c_str(), port);
    }
    bool EnableReadWrite(Connection *con, bool readable, bool writeable)
    {
        con->events_ = ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET);
        return epoller_.AddModEvent(con->fd_, con->events_, EPOLL_CTL_MOD);
    }
    // 连接管理
    void Accepter(Connection *con)
    {
        do
        {
            /* code */
            int err = 0;
            (void)con;
            // 1. 新连接到来
            // logMessage(Debug, "get a new link ...");
            std::string clientip;
            uint16_t clientport;
            int sock = listensock_.Accept(&clientip, &clientport, &err);
            if (sock > 0)
            {
                logMessage(Debug, "%s:%d 已经连上了服务器了", clientip.c_str(), clientport);
                // 1.1 此时在这里，我们能不能进行recv/read ? 不能，只有epoll知道sock上面的事件情况，将sock添加到epoll中
                AddConnection(sock, EPOLLIN | EPOLLET, clientip, clientport);
            }
            else
            {
                if (err == EAGAIN || err == EWOULDBLOCK)
                {
                    break;
                }
                else if (err == EINTR)
                    continue;
                else
                {
                    logMessage(Warning, "errstring:%d errcode:%d", strerror(err), err);
                    continue;
                }
            }

        } while (con->events_ & EPOLLET);
    }
    void HandlerRequest(Connection *con)
    {
        int quit = false;
        while (!quit)
        {
            string requestStr;
            // 1.提取完整报文
            int n = protocol_ns::ParsePackage(con->inbuffer_, &requestStr);
            if (n > 0)
            {
                // 2.提取有效载荷
                requestStr = protocol_ns::RemoveHeader(requestStr, n);
                // 反序列化
                Request req;
                req.Deserialize(requestStr);
                // 4.回调业务处理
                Response res = func_(req);
                // 5.序列化
                string RespStr;
                res.Serialize(&RespStr);
                // 6.添加包头
                RespStr = AddHeader(RespStr);
                // 进行返回
                con->outbuffer_ += RespStr;
            }
            else
                quit = true;
        }
    }
    void Recver(Connection *con)
    {
        do
        {
            /* code */
            char buffer[1024];
            ssize_t n = recv(con->fd_, buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                buffer[n] = 0;
                con->inbuffer_ += buffer;
            }
            else if (n == 0)
            {
                con->excepter_(con);
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    con->excepter_(con);
                    break;
                }
            }
        } while (con->events_ & EPOLLET);
        HandlerRequest(con);
        if (!con->outbuffer_.empty())
            con->sender_(con);
    }
    void Sender(Connection *con)
    {
        bool safe=true;
        do
        {
            ssize_t n = send(con->fd_, con->outbuffer_.c_str(), con->outbuffer_.size(), 0);
            if (n > 0)
            {
                con->outbuffer_.erase(0, n);
            }
            else
            {
                if ((errno == EAGAIN || errno == EWOULDBLOCK))
                {

                    break;
                }
                else if (errno == EINTR)
                    continue;
                else
                {
                    safe=false;
                    con->excepter_(con);
                    break;
                }
            }

        } while (con->events_ & EPOLLET);
        if(!safe) return ;
        if (!con->outbuffer_.empty())
            EnableReadWrite(con, true, true);
        else
            EnableReadWrite(con, true, false);
    }
    void Excepter(Connection *con)
    {
        //1.先从epoll中移除fd
        epoller_.DelEvent(con->fd_);
        //4.移除unordeermap中的kv关系
        connections_.erase(con->fd_);
        //2.关闭fd
        close(con->fd_);
        
        //3.connection对象释放掉
        delete con;

        
    }
    bool ConnIsExists(int fd)
    {
        return connections_.find(fd) != connections_.end();
    }

    ~EpollServer()
    {
        listensock_.Close();
        epoller_.Close();
    }

private:
    uint16_t port_;
    Sock listensock_;
    Epoller epoller_; // epoll模型
    // 定义一个捞取就绪事件的列表
    struct epoll_event revs_[gnum];
    func_t func_;
    unordered_map<int, Connection *> connections_;
};